using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace Comarch.Animation
{
    public partial class StoryboardBuilder
    {
        #region Scale, Transform, Rotate, ScaleToSize

        public StoryboardBuilder Rotate(FrameworkElement target, int degrees)
        {
            return Rotate(target, degrees, DefaultDuration);
        }

        public StoryboardBuilder Rotate(FrameworkElement target, int degrees, int duration)
        {
            return Rotate(target, degrees, duration, DefaultEasingFunction);
        }

        public StoryboardBuilder Rotate(FrameworkElement target, int degrees, int duration, IEasingFunction easingfunction)
        {
            TransformGroupOrigin(target);
            return AddDoubleKeyFrames(target, TransformationConsts.Rotation, degrees,  duration, easingfunction,true);
        }

        public StoryboardBuilder ScaleToSize(FrameworkElement target, int width, int height)
        {
            return ScaleToSize(target, width, height, DefaultDuration);
        }

        public StoryboardBuilder ScaleToSize(FrameworkElement target, int width, int height, int duration)
        {
            return ScaleToSize(target, width, height, duration, DefaultEasingFunction);
        }

        public StoryboardBuilder ScaleToSize(FrameworkElement target, int width, int height, int duration, IEasingFunction easingfunction)
        {
            return AddDoubleKeyFrames(target, TransformationConsts.Width, width, duration, easingfunction, false)
                .AddDoubleKeyFrames(target, TransformationConsts.Height, height, duration, easingfunction, false);
        }

        public StoryboardBuilder Scale(FrameworkElement target, double xScale, double yScale)
        {
            return Scale(target, xScale, yScale, DefaultDuration);
        }

        public StoryboardBuilder Scale(FrameworkElement target, double xScale, double yScale, int duration)
        {
            return Scale(target, xScale, yScale, duration, DefaultEasingFunction);
        }

        public StoryboardBuilder Scale(FrameworkElement target, double xScale, double yScale, int duration, IEasingFunction easingfunction)
        {
            TransformGroupOrigin(target);
            return AddDoubleKeyFrames(target, TransformationConsts.ScaleX, xScale,  duration, easingfunction, false).
                AddDoubleKeyFrames(target, TransformationConsts.ScaleY, yScale,  duration, easingfunction, false);
        }

        public StoryboardBuilder Translate(FrameworkElement target, int translateXPixels, int translateYPixels)
        {
            return Translate(target, translateXPixels, translateYPixels, DefaultDuration);
        }

        public StoryboardBuilder Translate(FrameworkElement target, int translateXPixels, int translateYPixels, int duration)
        {
            return Translate(target, translateXPixels, translateYPixels, duration, DefaultEasingFunction);
        }

        public StoryboardBuilder Translate(FrameworkElement target, int translateXPixels, int translateYPixels, int duration, IEasingFunction easingfunction)
        {
            TransformGroupOrigin(target);
            return AddDoubleKeyFrames(target, TransformationConsts.TranslateX, translateXPixels, duration, easingfunction, true).
                AddDoubleKeyFrames(target, TransformationConsts.TranslateY, translateYPixels, duration, easingfunction, true);
        }

        public StoryboardBuilder AbsoluteTranslate(FrameworkElement target, int translateXPixels, int translateYPixels)
        {
            return AbsoluteTranslate(target, translateXPixels, translateYPixels, DefaultDuration);
        }

        public StoryboardBuilder AbsoluteTranslate(FrameworkElement target, int translateXPixels, int translateYPixels, int duration)
        {
            return AbsoluteTranslate(target, translateXPixels, translateYPixels, duration, DefaultEasingFunction);
        }

        public StoryboardBuilder AbsoluteTranslate(FrameworkElement target, int translateXPixels, int translateYPixels, int duration, IEasingFunction easingfunction)
        {
            TransformGroupOrigin(target);
            var point = target.TransformToVisual(target.FindRoot<Panel>()).Transform(new Point());
            var x = target.GetValue(TransformationConsts.TranslateX);
            var y = target.GetValue(TransformationConsts.TranslateY);

            return AddDoubleKeyFrames(target, TransformationConsts.TranslateX, (int)(translateXPixels - (point.X-(double) x)),  duration, easingfunction,false).
                AddDoubleKeyFrames(target, TransformationConsts.TranslateY, (translateYPixels - (point.Y-(double) y)),  duration, easingfunction,false);
        }

        #endregion
        
        #region AnimateToRectangle, AnimateToControl

        public StoryboardBuilder AnimateToRectangle(FrameworkElement target, Rectangle rectangle)
        {
            return AnimateToRectangle(target, rectangle, DefaultDuration);
        }

        public StoryboardBuilder AnimateToRectangle(FrameworkElement target, Rectangle rectangle, int duration)
        {
            return AnimateToRectangle(target, rectangle, duration, DefaultEasingFunction);
        }

        public StoryboardBuilder AnimateToRectangle(FrameworkElement target, Rectangle rectangle, int duration, IEasingFunction easingfunction)
        {
            return Translate(target, TranslationCalculator.CalculateXTranslateDistance(target, rectangle), TranslationCalculator.CalculateYTranslateDistance(target, rectangle), duration, easingfunction)
                .ScaleToSize(target, (int)rectangle.ActualWidth, (int)rectangle.ActualHeight, duration, easingfunction);
        }

        public StoryboardBuilder AnimateToControl(FrameworkElement target, FrameworkElement destination)
        {
            return AnimateToControl(target, destination, DefaultDuration);
        }

        public StoryboardBuilder AnimateToControl(FrameworkElement target, FrameworkElement destination, int duration)
        {
            return AnimateToControl(target, destination, duration, DefaultEasingFunction);
        }

        public StoryboardBuilder AnimateToControl(FrameworkElement target, FrameworkElement destination, int duration, IEasingFunction easingfunction)
        {
            return Translate(target, TranslationCalculator.CalculateXTranslateDistance(target, destination),
                                     TranslationCalculator.CalculateYTranslateDistance(target, destination), duration,easingfunction)
             .ScaleToSize(target, (int)destination.ActualWidth, (int)destination.ActualHeight, duration, easingfunction);
        }

        #endregion

        #region Opacity, Show, Hide

        public StoryboardBuilder Opacity(FrameworkElement target, double value)
        {
            return Opacity(target, value, DefaultDuration);
        }

        public StoryboardBuilder Opacity(FrameworkElement target, double value, int duration)
        {
            return Opacity(target, value, duration, DefaultEasingFunction);
        }

        public StoryboardBuilder Opacity(FrameworkElement target, double value, int duration, IEasingFunction easingFunction)
        {
            return AddDoubleKeyFrames(target, TransformationConsts.Opacity, value,  duration, easingFunction,false);
        }

        public StoryboardBuilder Show(FrameworkElement target)
        {
            return Show(target, DefaultDuration);
        }

        public StoryboardBuilder Show(FrameworkElement target, int duration)
        {
            return Show(target, duration, DefaultEasingFunction);
        }

        public StoryboardBuilder Show(FrameworkElement target, int duration, IEasingFunction easingFunction)
        {
            return Opacity(target, 1, duration, easingFunction);
        }

        public StoryboardBuilder Hide(FrameworkElement target)
        {
            return Hide(target, DefaultDuration);
        }

        public StoryboardBuilder Hide(FrameworkElement target, int duration)
        {
            return Hide(target, duration, DefaultEasingFunction);
        }

        public StoryboardBuilder Hide(FrameworkElement target, int duration, IEasingFunction easingFunction)
        {
            return Opacity(target, 0, duration, easingFunction);
        }

        #endregion

        private void TransformGroupOrigin(FrameworkElement target)
        {
            if (target == null) throw new ArgumentNullException("target");
            target.RenderTransformOrigin = RenderTransformOrigin;

#if SL
            if (target.RenderTransform as CompositeTransform == null)
            {
                var compositeTransform = new CompositeTransform();
                target.RenderTransform = compositeTransform;
            }
#elif WPF
            if (target.RenderTransform != Transform.Identity) return;
            var tg = new TransformGroup();
            var rt = new RotateTransform();
            var st = new ScaleTransform();
            var tt = new TranslateTransform();
            tg.Children.Add(rt);
            tg.Children.Add(st);
            tg.Children.Add(tt);
            target.RenderTransform = tg;
#endif
        }
    }
}